﻿//-----------------------------------------------------------------------
// <copyright file="AccountTest.cs" company="FastNET Services">
//     Copyright (c) 2008-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
//-----------------------------------------------------------------------
#region Usings

using System;
using GateShift.Common.Repository.Interfaces.DataInterfaces;
using GateShift.Common.Repository.Interfaces.Repositories;
using GateShift.Services.GameFramework.GameObjects;
using GateShift.Testing.Mockup.DataLayer;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace GateShift.Testing.Services.GameFramework.GameObjects
{
    /// <summary>
    /// Summary description for AccountTest
    /// </summary>
    [TestClass]
    public class AccountTest
    {
        #region Test Variables
        private Account _account;
        private IAccountData _data;
        private MockRepositoryFactory _factory;
        #endregion

        #region Test Properties
        /// <summary>
        /// Gets or sets the test context which provides
        /// information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext { get; set; }
        #endregion

        #region Test Initialization/Cleanup

        [TestInitialize]
        public void TestInitialize()
        {
            _factory = new MockRepositoryFactory();
            _data = new MockAccount();

            MockRepositoryFactory.TestInitialize();

            // Set up basic load mocks
            MockRepositoryFactory.GetMock<IAccountRepository>().Expect(item => item.Create()).Returns(_data);

            _account = new Account(_factory);
        }

        [TestCleanup]
        public void TestCleanup()
        {
            MockRepositoryFactory.TestCleanup();
            _account = null;
        }

        #endregion

        #region AccountName

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AccountName_Null()
        {
            _account.AccountName = null;
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AccountName_Empty()
        {
            _account.AccountName = string.Empty;
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void AccountName_FirstPositionNumber()
        {
            _account.AccountName = "1Name";
        }

        [TestMethod]
        [ExpectedException(typeof(IndexOutOfRangeException))]
        public void AccountName_TooLong()
        {
            _account.AccountName = string.Empty.PadRight(51, 'A');
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void AccountName_InvalidCharacters()
        {
            _account.AccountName = "!";
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void AccountName_Spaces()
        {
            _account.AccountName = "A Spaced Name";
        }

        [TestMethod]
        public void AccountName_Success()
        {
            _account.AccountName = "A123Thisisa123longna";
        }

        #endregion

        #region Comment

        [TestMethod]
        public void Comment_Null()
        {
            _account.Comment = null;
        }

        [TestMethod]
        public void Comment_Success()
        {
            _account.Comment = "A123Thisisa123longna @$#!$%";
        }

        #endregion

        #region EmailAddress

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void EmailAddress_Null()
        {
            _account.EmailAddress = null;
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void EmailAddress_Empty()
        {
            _account.EmailAddress = string.Empty;
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void EmailAddress_FailsRegEx_NoDomain()
        {
            _account.EmailAddress = "1Name";
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void EmailAddress_FailsRegEx_InvalidUserCharacters()
        {
            _account.EmailAddress = "!@#$%^&*()+=`~root@somewhere.com";
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void EmailAddress_FailsRegEx_InvalidDomainCharacters()
        {
            _account.EmailAddress = "root@!@#$%^&*()+=`~";
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void EmailAddress_InvalidCharacters()
        {
            _account.EmailAddress = "!@!#$^%#!^$#";
        }

        [TestMethod]
        [ExpectedException(typeof(FormatException))]
        public void EmailAddress_Spaces()
        {
            _account.EmailAddress = "A Spaced Name";
        }

        [TestMethod]
        public void EmailAddress_Success()
        {
            _account.EmailAddress = "name@localhost";
            _account.EmailAddress = "name@localhost.com";
            _account.EmailAddress = "first.last@localhost";
            _account.EmailAddress = "first.last@localhost.com";
            _account.EmailAddress = "first.last@localhost.net";
            _account.EmailAddress = "first.last@localhost.local";
            _account.EmailAddress = "first.last@127.0.0.1";
        }

        #endregion

        #region Locking

        [TestMethod]
        public void Locked_Default()
        {
            Assert.IsFalse(_account.Locked);
        }

        [TestMethod]
        public void Locked_Success_PermaLock()
        {
            _account.LockAccount();

            Assert.IsTrue(_account.Locked, "Business Invalid");
        }

        [TestMethod]
        public void Locked_Success_Dated()
        {
            _account.LockAccount(DateTime.UtcNow.AddDays(1));

            Assert.IsTrue(_account.Locked, "Business Invalid");
        }

        [TestMethod]
        public void Locked_PermaBeforeDate()
        {
            _account.LockAccount(DateTime.UtcNow.AddDays(-1));
            _account.LockAccount();

            Assert.IsTrue(_account.Locked, "Business Invalid");
            Assert.IsTrue(_account.DateLockedUntil < DateTime.UtcNow, "Business Invalid");
        }

        [TestMethod]
        public void Locked_UntilExpired()
        {
            _account.LockAccount(DateTime.UtcNow.AddDays(-1));

            Assert.IsFalse(_account.Locked, "Business Invalid");
            Assert.IsTrue(_account.DateLockedUntil < DateTime.UtcNow, "Business Invalid");
        }

        [TestMethod]
        public void Locked_UpdatesData_PermaLock()
        {
            _account.LockAccount();

            Assert.IsTrue(_data.Locked, "Data Invalid");
        }

        [TestMethod]
        public void Locked_UpdatesData_Dated()
        {
            DateTime lockDate = DateTime.UtcNow.AddDays(1);
            _account.LockAccount(lockDate);

            Assert.AreEqual(lockDate, _data.DateLockedUntil, "Data Invalid");
        }

        [TestMethod]
        public void Locked_UpdatesLockoutDate()
        {
            Assert.IsNull(_data.DateLastLocked, "Date is not Null");

            _account.LockAccount();

            Assert.IsNotNull(_data.DateLastLocked, "Date Null");
        }

        [TestMethod]
        public void Locked_ResetLockoutDate()
        {
            _data.DateLastLocked = DateTime.UtcNow;
            Assert.IsNotNull(_data.DateLastLocked, "Date Null");

            _account.ResetLockoutDate();

            Assert.IsNull(_data.DateLastLocked, "Date is not Null");
        }

        #endregion

        #region Banning

        [TestMethod]
        public void Banned_Default()
        {
            Assert.IsFalse(_account.Banned);
        }

        [TestMethod]
        public void Banned_Success_PermaLock()
        {
            _account.BanAccount();

            Assert.IsTrue(_account.Banned, "Business Invalid");
        }

        [TestMethod]
        public void Banned_Success_Dated()
        {
            _account.BanAccount(DateTime.UtcNow.AddDays(1));

            Assert.IsTrue(_account.Banned, "Business Invalid");
        }

        [TestMethod]
        public void Banned_PermaBeforeDate()
        {
            _account.BanAccount(DateTime.UtcNow.AddDays(-1));
            _account.BanAccount();

            Assert.IsTrue(_account.Banned, "Business Invalid");
            Assert.IsTrue(_account.DateBannedUntil < DateTime.UtcNow, "Business Invalid");
        }

        [TestMethod]
        public void Banned_UntilExpired()
        {
            _account.BanAccount(DateTime.UtcNow.AddDays(-1));

            Assert.IsFalse(_account.Banned, "Business Invalid");
            Assert.IsTrue(_account.DateBannedUntil < DateTime.UtcNow, "Business Invalid");
        }

        [TestMethod]
        public void Banned_UpdatesData_PermaLock()
        {
            _account.BanAccount();

            Assert.IsTrue(_data.Banned, "Data Invalid");
        }

        [TestMethod]
        public void Banned_UpdatesData_Dated()
        {
            DateTime banDate = DateTime.UtcNow.AddDays(1);
            _account.BanAccount(banDate);

            Assert.AreEqual(banDate, _data.DateBannedUntil, "Data Invalid");
        }

        [TestMethod]
        public void Banned_UpdatesLockoutDate()
        {
            Assert.IsNull(_data.DateLastBanned, "Date is not Null");

            _account.BanAccount();

            Assert.IsNotNull(_data.DateLastBanned, "Date Null");
        }

        [TestMethod]
        public void Banned_ResetLockoutDate()
        {
            _data.DateLastBanned = DateTime.UtcNow;
            Assert.IsNotNull(_data.DateLastBanned, "Date Null");

            _account.ResetBannedDate();

            Assert.IsNull(_data.DateLastBanned, "Date is not Null");
        }

        #endregion

        #region PasswordSalt Based

        [TestMethod]
        public void PasswordSalt_Default()
        {
            // Shouldnt be null because constructor of a new object should generate
            Assert.IsNotNull(_data.PasswordSalt);
        }

        [TestMethod]
        public void PasswordSalt_Success()
        {
            byte[] oldSalt = _data.PasswordSalt;

            // Shouldnt be null because constructor of a new object should generate
            Assert.AreEqual(_data.PasswordSalt, oldSalt, "Not Comparable");

            // Reset the salt to a new value
            _account.GenerateNewSalt();

            // Shouldnt be null because constructor of a new object should generate
            Assert.AreNotEqual(oldSalt, _data.PasswordSalt, "Data Matches");
        }

        #endregion

        #region Locked

        [TestMethod]
        public void DateLastLogin_Default()
        {
            Assert.IsNull(_account.DateLastLogin, "Date is not null");
        }

        [TestMethod]
        public void DateLastLogin_UpdateSuccess()
        {
            _account.UpdateLoginDate();

            Assert.IsNotNull(_data.DateLastLogin, "Date is null");
        }

        [TestMethod]
        public void DateLastLogin_ResetLoginDate()
        {
            _data.DateLastLogin = DateTime.UtcNow;
            Assert.IsNotNull(_data.DateLastLogin, "Date Null");

            _account.ResetLoginDate();

            Assert.IsNull(_data.DateLastLogin, "Date is not Null");
        }

        #endregion

        #region Password Based

        [TestMethod]
        public void Password_Default()
        {
            Assert.IsNull(_data.Password);
        }

        [TestMethod]
        public void Password_Success()
        {
            _account.SetPassword("NewPassword");

            Assert.IsNotNull(_data.Password, "Data is null");
        }

        [TestMethod]
        public void Password_Validate()
        {
            _account.SetPassword("NewPassword");

            Assert.IsTrue(_account.ValidatePassword("NewPassword"), "Password stored incorrectly");
        }

        #endregion

        #region DateCreated

        [TestMethod]
        public void DateCreated_Default()
        {
            // Shouldnt be "null" because constructor of a new object should generate
            Assert.AreNotEqual(DateTime.MinValue, _data.DateCreated, "Data Matches");
        }

        #endregion

        #region ResetInvalidPasswordAttempts

        [TestMethod]
        public void ResetInvalidPasswordAttempts()
        {
            _data.FailedPasswordAttemptCount = 10;

            _account.ResetInvalidPasswordAttempts();

            Assert.AreEqual(0, _data.FailedPasswordAttemptCount, "Data Matches");
        }

        #endregion

        #region ResetDateLastPasswordChanged

        [TestMethod]
        public void ResetDateLastPasswordChanged()
        {
            _data.DateLastPasswordChanged = DateTime.UtcNow;

            _account.ResetDateLastPasswordChanged();

            Assert.AreEqual(null, _data.DateLastPasswordChanged, "Data Matches");
        }

        #endregion
    }
}